﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;

namespace SRB.Tg.Operate
{
    class FilesUtiles
    {
        public SortedDictionary<string, object> FromXml(string xml)
        {
            SortedDictionary<string, object> m_values = new SortedDictionary<string, object>();
            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.LoadXml(xml);
            XmlNode xmlNode = xmlDoc.FirstChild;//获取到根节点<xml>
            XmlNodeList nodes = xmlNode.ChildNodes;
            foreach (XmlNode xn in nodes)
            {
                XmlElement xe = (XmlElement)xn;
                m_values[xe.Name] = xe.InnerText;//获取xml的键值对到WxPayData内部的数据中
            }
            return m_values;
        }

        public static Dictionary<string, string> XML2DIc(string _xml)
        {
            Dictionary<string, string> _dictionary = new Dictionary<string, string>();
            using (XmlReader reader = XmlReader.Create(_xml))
            {
                while (reader.Read())
                {
                    if (reader.NodeType == XmlNodeType.Element && reader.LocalName == "data")
                    {
                        reader.MoveToAttribute("name");
                        string key = reader.Value;
                        reader.MoveToContent();
                        string value = reader.ReadElementContentAsString();
                        _dictionary.Add(key, value);
                    }
                }
                reader.Close();
            }
            return _dictionary;
        }
        /// <summary>
        /// xml文档对象转换到Dictionary<string,object>或list
        /// 拥有重复名称子节点的节点会被转换成list，而忽略子节点的名称
        /// </summary>
        /// <param name="xml_doc">xml文档对象</param>
        /// <param name="dso">保存Dictionary的对象</param>
        public static void XmlToDictionaryOrList(XmlDocument xml_doc, object dso)
        {
            if (xml_doc == null || xml_doc.DocumentElement == null || dso == null)
            {
                return;
            }

            XmlToDictionaryOrListWithOutAttributes(xml_doc.DocumentElement, dso);
        }

        /// <summary>
        /// 转换当前节点为字典或list
        /// </summary>
        /// <param name="xn"></param>
        /// <param name="dso"></param>
        private static void XmlToDictionaryOrListWithOutAttributes(XmlNode xn, object dso)
        {

            XmlNodeList xnl = xn.ChildNodes;
            List<object> list = null;
            Dictionary<string, object> dic = null;

            if (dso is Dictionary<string, object>)
            {
                dic = dso as Dictionary<string, object>;
            }
            else
            {
                list = dso as List<object>;
            }

            object temp = null;


            // 如果没有子节点了，退出递归的条件
            // 后一个条件是为了忽略xml的强制数据条件<![CDATA[...]]>，不把它当作子节点处理
            if (xnl.Count == 0 || xn.InnerText == xn.InnerXml)
            {
                //如果本节点是字典类型
                if (dic != null)
                {
                    // 添加键值对
                    dic.Add(xn.Name, xn.InnerText);
                }
                // 如果本节点是list类型，直接添加值，忽略键
                else if (list != null)
                {
                    list.Add(xn.InnerText);
                }
                else
                {
                    throw new Exception("转换失败");
                }

                return;
            }
            else
            {
                // 如果有重复的子节点
                if (XmlNodeHasDuplicateChild(xn))
                {
                    // 装子节点的对象为list
                    temp = new List<object>();
                }
                else
                {
                    temp = new Dictionary<string, object>();
                }

                if (dic != null)
                {
                    // 以空字典添加节点
                    dic.Add(xn.Name, temp);
                }
                else if (list != null)
                {

                    list.Add(temp);
                }
                else
                {
                    throw new Exception("转换失败");
                }

            }


            // 子节点递归
            for (int i = 0; i < xnl.Count; i++)
            {
                XmlToDictionaryOrListWithOutAttributes(xnl[i], temp);
            }
        }


        /// <summary>
        /// XmlNode下有无重复子节点
        /// </summary>
        /// <param name="xn"></param>
        /// <returns></returns>
        public static bool XmlNodeHasDuplicateChild(XmlNode xn)
        {

            Dictionary<string, string> temp = new Dictionary<string, string>();

            for (int i = 0; i < xn.ChildNodes.Count; i++)
            {
                if (temp.ContainsKey(xn.ChildNodes[i].Name))
                {
                    return true;
                }
                temp[xn.ChildNodes[i].Name] = "重复节点";
            }

            return false;
        }

        public static String UTF8ByteArrayToString(byte[] characters)
        {
            UTF8Encoding encoding = new UTF8Encoding();
            String constructedString = encoding.GetString(characters);
            return (constructedString);
        }

        public static byte[] StringToUTF8ByteArray(String pXmlString)
        {
            UTF8Encoding encoding = new UTF8Encoding();
            byte[] byteArray = encoding.GetBytes(pXmlString);
            return byteArray;
        }

        public static String SerializeObject<T>(object pObject)
        {
            String XmlizedString = "";
            MemoryStream memoryStream = new MemoryStream();
            XmlSerializer xs = new XmlSerializer(typeof(T));
            XmlTextWriter xmlTextWriter = new XmlTextWriter(memoryStream, Encoding.UTF8);
            xs.Serialize(xmlTextWriter, pObject);
            memoryStream = (MemoryStream)xmlTextWriter.BaseStream; // (MemoryStream)
            XmlizedString = UTF8ByteArrayToString(memoryStream.ToArray());
            return XmlizedString;
        }

        public static object DeserializeObject<T>(String pXmlizedString)
        {

            XmlSerializer xs = new XmlSerializer(typeof(T));
            MemoryStream memoryStream = new MemoryStream(StringToUTF8ByteArray(pXmlizedString));
            XmlTextWriter xmlTextWriter = new XmlTextWriter(memoryStream, Encoding.UTF8);
            return xs.Deserialize(memoryStream);
        }


        [XmlRoot("dictionary"), Serializable]
        public class SerializableDictionary<TKey, TValue>: Dictionary<TKey, TValue>, IXmlSerializable
        {
            public SerializableDictionary()
            {

            }

            public SerializableDictionary(IDictionary<TKey, TValue> dictionary): base(dictionary)
            {
            }

            public SerializableDictionary(IEqualityComparer<TKey> comparer)
            : base(comparer)
            {
            }

            public SerializableDictionary(int capacity): base(capacity)
            {
            }

            public SerializableDictionary(int capacity, IEqualityComparer<TKey> comparer)
            : base(capacity, comparer)
            {
            }

            protected SerializableDictionary(SerializationInfo info, StreamingContext context)
            : base(info, context)
            {

            }

            #region IXmlSerializable Members

            public XmlSchema GetSchema()
            {
                return null;
            }
            /// <summary>
            /// 从对象的 XML 表示形式生成该对象
            /// </summary>
            /// <param name="reader"></param>
            public void ReadXml(XmlReader reader)
            {

                var keySerializer = new XmlSerializer(typeof(TKey));
                var valueSerializer = new XmlSerializer(typeof(TValue));
                bool wasEmpty = reader.IsEmptyElement;
                reader.Read();
                if (wasEmpty)
                    return;
                while (reader.NodeType != XmlNodeType.EndElement)
                {
                    reader.ReadStartElement("item");
                    reader.ReadStartElement("key");
                    var key = (TKey)keySerializer.Deserialize(reader);
                    reader.ReadEndElement();
                    reader.ReadStartElement("value");
                    var value = (TValue)valueSerializer.Deserialize(reader);
                    reader.ReadEndElement();
                    Add(key, value);
                    reader.ReadEndElement();
                    reader.MoveToContent();
                }
                reader.ReadEndElement();
            }

            /// <summary>
            /// 将对象转换为其 XML 表示形式
            /// </summary>
            /// <param name="writer"></param>
            public void WriteXml(XmlWriter writer)
            {
                var keySerializer = new XmlSerializer(typeof(TKey));
                var valueSerializer = new XmlSerializer(typeof(TValue));
                foreach (TKey key in Keys)
                {
                    writer.WriteStartElement("item");
                    writer.WriteStartElement("key");
                    keySerializer.Serialize(writer, key);
                    writer.WriteEndElement();
                    writer.WriteStartElement("value");
                    TValue value = this[key];
                    valueSerializer.Serialize(writer, value);
                    writer.WriteEndElement();
                    writer.WriteEndElement();
                }
            }

            #endregion
        }
    }
}